package client;

import client.handle.ClienInboundHandle;
import client.handle.ClientToCenterInboundHandle;
import codec.DataDecode;
import codec.DataEncode;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import server.handle.DataInboundHandle;
import support.RpcInfo;
import util.StringUtil;

import java.util.concurrent.*;

public class RpcClient {
    Bootstrap bootstrap;
    ChannelFuture future;
    String host;
    int port;

    static NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();

    static Logger logger = LoggerFactory.getLogger(RpcClient.class);

    public boolean ftSts(){
        return future!=null && future.isSuccess();
    }

    public RpcClient(String host, int port, SimpleChannelInboundHandler handler){
        this.port = port;
        this.host=host;

        bootstrap = new Bootstrap();
        bootstrap = bootstrap.group(nioEventLoopGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                ch.pipeline().addLast(new DataDecode());
                ch.pipeline().addLast(new DataEncode());
                ch.pipeline().addLast(handler);
            }
        });
    }

    public void conn() throws Exception {

        try {
            future = bootstrap.connect(host, port).sync();
            logger.info("连接成功...");
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    public void closeCLinet() throws InterruptedException {
        future.channel().closeFuture().sync();
    }

    public synchronized RpcInfo send(RpcInfo rpcInfo){
        NioSocketChannel channel = (NioSocketChannel) future.channel();
        ClienInboundHandle clienInboundHandle = channel.pipeline().get(ClienInboundHandle.class);

        //  当服务端下线重连时，如果客户端在次发起请求，若之前调用成功过，则会缓存与服务端的连接，会从缓存取到连接，但显然这种情况下连接已经失效了，需要重新连接
        //(已解决..当缓存服务端连接掉线，自动关闭当前连接并从缓存删除)
        clienInboundHandle.setFuture(new CompletableFuture<>());
        channel.writeAndFlush(rpcInfo);
        RpcInfo resInfo = null;
        try {
            resInfo = clienInboundHandle.getFuture().get(StringUtil.TIME_OUT, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            return resInfo;
        }
    }

    public synchronized RpcInfo sendToCenter(RpcInfo rpcInfo) throws Exception {
        logger.info("发送注册中心...");
        NioSocketChannel channel = (NioSocketChannel) future.channel();
        ClientToCenterInboundHandle clientToCenterInboundHandle = channel.pipeline().get(ClientToCenterInboundHandle.class);

        clientToCenterInboundHandle.setFuture(new CompletableFuture<>());

        //把本地端口写入
        rpcInfo.setServerToCenterPort(channel.localAddress().getPort());

        channel.writeAndFlush(rpcInfo);
        RpcInfo resInfo = null;
        try {
            resInfo = clientToCenterInboundHandle.getFuture().get(StringUtil.TIME_OUT, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            return resInfo;
        }
    }


}
